package com.sso.manager;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sso.entity.*;
import com.sso.entity.vo.SysUserVo;
import com.sso.shiro.RealmManager;
import com.tools.util.BeanUtils;
import com.tools.util.MD5Utils;
import com.tools.util.StrUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.sso.common.ConstantDate;
import com.sso.common.enums.FlagStatus;
import com.sso.dao.SysUserMapper;
import com.sso.exception.SelectException;

@Service
public class SysUserManager {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private SysUserMapper dao;
	@Autowired
	private SysUserRoleManager userRoleManager;
	@Autowired
	private SysUserMenuManager userMenuManager;


	/**
	 * 用户登陆，返回登陆成功（T）或者错误信息
	 * @param username
	 * @param password
     * @return
     */
	public String login(String username,String password){
		try{
			UsernamePasswordToken token = new UsernamePasswordToken(username,password);
			Subject user = SecurityUtils.getSubject();
			user.login(token);
			return FlagStatus.SUCCESS.value;
		}catch(UnknownAccountException e){
			return "账户名密码错误";
		}catch(IncorrectCredentialsException e){
			return "账户名密码错误";
		}catch (ExcessiveAttemptsException e) {
			return "失败次数过多，请稍候重试";
		}catch (LockedAccountException e) {
			return "账户被锁定";
		}catch(DisabledAccountException e){
			return "账户被禁用";
		}
	}

	/**
	 * 保存用户方法，如果ID为空则为新增
	 * @param user
	 * @return
	 * @throws Exception
     */
	@Transactional(rollbackFor = Exception.class)
	public String save(SysUser user) throws Exception {
		if(StrUtils.isEmpty(user.getId())){
			user.setId(ConstantDate.getUUID());
			user.setCreateTime(new Date());
			user.setPassword(MD5Utils.MD5(user.getPassword()));
			dao.insert(user);
		}else{
			dao.update(user);
		}
		return FlagStatus.SUCCESS.value;
	}

	/**
	 * 根据ID查询
	 * @param id
	 * @return
     */
	@Transactional(propagation=Propagation.SUPPORTS)
	public SysUser selectById(String id){
		if(StrUtils.isEmpty(id)){
			return new SysUser();
		}
		Map<String,Object> param = new HashMap<String, Object>();
		param.put("id", id);
		return this.selectByUnique(param);
	}

	/**
	 * 根据username查询
	 * @param username
	 * @return
     */
	@Transactional(propagation=Propagation.SUPPORTS)
	public SysUser selectByUsername(String username){
		Map<String,Object> param = new HashMap<String, Object>();
		param.put("username", username);
		return this.selectByUnique(param);
	}

	/**
	 * 查询用户转成Vo
	 * @param username
	 * @return
     */
	@Transactional(propagation=Propagation.SUPPORTS)
	public SysUserVo selectByUsernameToVo(String username){
		SysUser user = this.selectByUsername(username);
		SysUserVo userVo =BeanUtils.copyBean(user,SysUserVo.class);
		return userVo;
	}

	/**
	 * 分页查询
	 * @param filterMap
	 * @return
	 * @throws SelectException
     */
	@Transactional(propagation=Propagation.SUPPORTS)
	public Page<SysUser> selectByPage(Map<String,Object> filterMap) throws SelectException {
		String pageNo = (String) filterMap.get("pageNo");
		String pageSize = (String) filterMap.get("pageSize");
		Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
		filterMap.put("first", page.getFirst());
		filterMap.put("last", page.getLast());
		List<SysUser>list = dao.selectByPage(filterMap);
		Long count = dao.countByProperty(filterMap);
		page.setData(list);
		page.setTotalCount(count);
		return page;
	}

	/**
	 * 分页查询系统用户列表
	 * @param filterMap
	 * @return Page<SysUserVo>
     */
	public Page<SysUserVo> selectByPageToVo(Map<String,Object> filterMap) throws SelectException {
		Page<SysUserVo> page = new Page<SysUserVo>(filterMap);
		List<SysUserVo>list = dao.selectByPageToVo(page.getParamMap());
		Long count = dao.countByProperty(page.getParamMap());
		page.setData(list);
		page.setTotalCount(count);
		return page;
	}

	/**
	 * 唯一字段查询方法
	 * 使用此方法必须保证查询字段的值在表中唯一否则会报查询异常。
	 * @param param
	 * @return
	 * @throws SelectException
	 */
	@Transactional(propagation=Propagation.SUPPORTS)
	private SysUser selectByUnique(Map<String,Object> param){
		List<SysUser> userList = dao.selectByProperty(param);
		/*如果查询出来的集合等于null或者大于1则打印错误信息返回则null*/
		if(userList==null || userList.size()==0){
			return new SysUser();
		}else if(userList==null ||userList.size()>1){
			logger.info("SysUserManager selectByUnique error msg:用户查询错误，数据查询不唯一，大小为："+userList.size());
			return new SysUser();
		}
		return userList.get(0);
	}

	/**
	 * 保存用户所拥有的角色权限
	 * @param roleList
	 * @param user
	 * @return
	 * @throws SelectException
	 */
	@Transactional(rollbackFor=Exception.class)
	public int saveUserRole(List<SysRole> roleList, SysUser user) throws Exception {
		int row =userRoleManager.deleteByUserId(user.getId());
		for(SysRole role: roleList){
			SysUserRole userRole = new SysUserRole(user.getId(),role.getId());
			userRoleManager.save(userRole);
		}
		this.clearUserAuthByUsername(user.getUsername());
		return row;
	}

	/**
	 * 保存用户所拥有的菜单权限
	 * @param menuList
	 * @param user
     * @return
     */
	public int saveUserMenu(List<SysMenu> menuList, SysUser user) throws Exception {
		int row =userMenuManager.deleteByUserId(user.getId());
		for(SysMenu menu: menuList){
			SysUserMenu usermenu = new SysUserMenu(user.getId(),menu.getId());
			userMenuManager.save(usermenu);
		}
		this.clearUserAuthByUsername(user.getUsername());
		return 1;
	}

	/**
	 * 清除指定用户的权限
	 * @param username
	 */
	public void clearUserAuthByUsername(String username){
		RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
		RealmManager realm = (RealmManager) rsm.getRealms().iterator().next();
		realm.clearUserChache(username);
	}

	/**
	 * 清除所有用户权限
	 */
	public void clearAllUserAuth(){
		RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
		RealmManager realm = (RealmManager) rsm.getRealms().iterator().next();
		realm.clearAllUserCache();
	}

}
